package com.palmshop.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import net.sf.json.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

/**
 * 微信公众号相关工具类
 * 
 * @author Administrator
 * 
 */
public class TokenUtil {

	public static final String APPID = ResourceBundle.getBundle("weixin").getString("weixin.appid");// 应用ID

	public static final String SECRET = ResourceBundle.getBundle("weixin").getString("weixin.secret");// 应用密钥

	private static final Logger logger = Logger.getLogger(TokenUtil.class.getName());

	private static CloseableHttpClient createSSLClientDefault() {
		try {
			SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
				// 信任所有
				@Override
				public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
					return true;
				}
			}).build();
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
			return HttpClients.custom().setSSLSocketFactory(sslsf).build();
		} catch (KeyManagementException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (KeyStoreException e) {
			e.printStackTrace();
		}
		return HttpClients.createDefault();
	}

	public static String getAccessToken() {
		String access_token = "";
		try {
			access_token = PropertiesLoaderUtils.loadAllProperties("weixin.properties").getProperty("weixin.access_token");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if ("0".equals(access_token)) {
			updateTokens();
		}
		return access_token;
	}

	private static String getTokensFromServer(final String url, final String key) {
		String result = "";
		CloseableHttpClient httpclient = createSSLClientDefault();
		HttpGet httpget = new HttpGet(url.toString());
		try {
			CloseableHttpResponse response = httpclient.execute(httpget);
			HttpEntity entity = response.getEntity();

			if (entity != null) {

				BufferedReader in = new BufferedReader(new InputStreamReader(entity.getContent()));
				String line = null;

				while ((line = in.readLine()) != null) {
					result += line + "\n";
				}

				in.close();
				if (result.contains(key)) {
					JSONObject json_token = JSONObject.fromObject(result);
					result = json_token.getString(key);
				} else {
					result = "0";
				}
			}
			response.close();
		} catch (ClientProtocolException e) {
			throw new RuntimeException("网络状况异常,访问失败!");
		} catch (UnsupportedEncodingException e1) {
			throw new RuntimeException("字符编码错误,访问失败!");
		} catch (IOException e) {
			throw new RuntimeException("网络状况异常,访问失败!");
		} finally {
			// 关闭连接,释放资源
			try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return result;
	}

	public static String getJSAPITicket() {
		String jsapi_ticket = "";
		try {
			jsapi_ticket = PropertiesLoaderUtils.loadAllProperties("weixin.properties").getProperty("weixin.jsapi_ticket");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if ("0".equals(jsapi_ticket)) {
			updateTokens();
		}
		return jsapi_ticket;
	}

	/**
	 * 传递键值对的Map，更新properties文件
	 * 
	 * @param fileName
	 *            文件名(放在resource源包目录下)，需要后缀
	 * @param keyValueMap
	 *            键值对Map
	 */
	private static void updateProperties(String fileName, Map<String, String> keyValueMap) {
		// getResource方法使用了utf-8对路径信息进行了编码，当路径中存在中文和空格时，他会对这些字符进行转换，这样，
		// 得到的往往不是我们想要的真实路径，在此，调用了URLDecoder的decode方法进行解码，以便得到原始的中文及空格路径。
		String filePath = TokenUtil.class.getClassLoader().getResource(fileName).getFile();
		Properties props = null;
		BufferedWriter bw = null;

		try {
			filePath = URLDecoder.decode(filePath, "utf-8");
			props = PropertiesLoaderUtils.loadProperties(new ClassPathResource(fileName));

			// 写入属性文件
			bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath)));

			// props.clear();// 清空旧的文件

			for (String key : keyValueMap.keySet()) {
				props.setProperty(key, keyValueMap.get(key));
			}

			props.store(bw, "");
		} catch (IOException e) {
		} finally {
			try {
				bw.close();

				logger.info("weixin.properties更新完毕！");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void updateTokens() {
		String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APPID + "&secret=" + SECRET;
		String token = getTokensFromServer(url, "access_token");

		Map<String, String> m = new HashMap<String, String>();
		m.put("weixin.access_token", token);
		logger.info("access_token >>>>> " + token);
		url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + token + "&type=jsapi";
		String ticket = getTokensFromServer(url, "ticket");
		logger.info("jsapi_ticket >>>>> " + ticket);
		m.put("weixin.jsapi_ticket", ticket);
		updateProperties("weixin.properties", m);
	}

	private TokenUtil() {

	}
}
